home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 8: LINUX Games / Linux Cubed Series 8 - LINUX Games.iso / games / x11 / video / xonix-1.0 / xonix-1 / xonix / xgifload.c < prev    next >
C/C++ Source or Header  |  1995-07-31  |  15KB  |  589 lines

  1. /*
  2.  * xgifload.c  -  based strongly on...
  3.  *
  4.  * gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image.
  5.  *
  6.  * Copyright (c) 1988, 1989 by Patrick J. Naughton
  7.  *
  8.  * Author: Patrick J. Naughton
  9.  * naughton@wind.sun.com
  10.  *
  11.  * Permission to use, copy, modify, and distribute this software and its
  12.  * documentation for any purpose and without fee is hereby granted,
  13.  * provided that the above copyright notice appear in all copies and that
  14.  * both that copyright notice and this permission notice appear in
  15.  * supporting documentation.
  16.  *
  17.  * This file is provided AS IS with no warranties of any kind.  The author
  18.  * shall have no liability with respect to the infringement of copyrights,
  19.  * trade secrets or any patents by this file or any part thereof.  In no
  20.  * event will the author be liable for any lost revenue or profits or
  21.  * other special, indirect and consequential damages.
  22.  *
  23.  */
  24.  
  25. #include "xgif.h"
  26.  
  27. typedef int boolean;
  28.  
  29. #define NEXTBYTE (*ptr++)
  30. #define IMAGESEP 0x2c
  31. #define INTERLACEMASK 0x40
  32. #define COLORMAPMASK 0x80
  33.  
  34. FILE *fp;
  35.  
  36. int BitOffset = 0,        /* Bit Offset of next code */
  37.   XC = 0, YC = 0,        /* Output X and Y coords of current pixel */
  38.   Pass = 0,            /* Used by output routine if interlaced pic */
  39.   OutCount = 0,            /* Decompressor output 'stack count' */
  40.   RWidth, RHeight,        /* screen dimensions */
  41.   Width, Height,        /* image dimensions */
  42.   LeftOfs, TopOfs,        /* image offset */
  43.   BitsPerPixel,            /* Bits per pixel, read from GIF header */
  44.   BytesPerScanline,        /* bytes per scanline in output raster */
  45.   ColorMapSize,            /* number of colors */
  46.   Background,            /* background color */
  47.   CodeSize,            /* Code size, read from GIF header */
  48.   InitCodeSize,            /* Starting code size, used during Clear */
  49.   Code,                /* Value returned by ReadCode */
  50.   MaxCode,            /* limiting value for current code size */
  51.   ClearCode,            /* GIF clear code */
  52.   EOFCode,            /* GIF end-of-information code */
  53.   CurCode, OldCode, InCode,    /* Decompressor variables */
  54.   FirstFree,            /* First free code, generated per GIF spec */
  55.   FreeCode,            /* Decompressor, next free slot in hash table */
  56.   FinChar,            /* Decompressor variable */
  57.   BitMask,            /* AND mask for data size */
  58.   ReadMask;            /* Code AND mask for current code size */
  59.  
  60. boolean Interlace, HasColormap;
  61. boolean Verbose = False;
  62.  
  63. byte *Image;            /* The result array */
  64. byte *RawGIF;            /* The heap array to hold it, raw */
  65. byte *Raster;            /* The raster data stream, unblocked */
  66.  
  67.     /* The hash table used by the decompressor */
  68. int Prefix[4096];
  69. int Suffix[4096];
  70.  
  71.     /* An output array used by the decompressor */
  72. int OutCode[1025];
  73.  
  74.     /* The color map, read from the GIF header */
  75. byte Red[256], Green[256], Blue[256], used[256];
  76. int numused;
  77.  
  78. char *id = "GIF87a";
  79.  
  80.  
  81.  
  82. /*****************************/
  83. LoadGIF (fname)
  84.      char *fname;
  85. /*****************************/
  86. {
  87.   int filesize;
  88.   register byte ch, ch1;
  89.   register byte *ptr, *ptr1;
  90.   register int i;
  91.  
  92.   if (strcmp (fname, "-") == 0)
  93.     {
  94.       fp = stdin;
  95.       fname = "<stdin>";
  96.     }
  97.   else
  98.     fp = fopen (fname, "r");
  99.  
  100.   if (!fp)
  101.     FatalError ("file not found");
  102.  
  103.   /* find the size of the file */
  104.   fseek (fp, 0L, 2);
  105.   filesize = ftell (fp);
  106.   fseek (fp, 0L, 0);
  107.  
  108.   if (!(ptr = RawGIF = (byte *) malloc (filesize)))
  109.     FatalError ("not enough memory to read gif file");
  110.  
  111.   if (!(Raster = (byte *) malloc (filesize)))
  112.     FatalError ("not enough memory to read gif file");
  113.  
  114.   if (fread (ptr, filesize, 1, fp) != 1)
  115.     FatalError ("GIF data read failed");
  116.  
  117.   if (strncmp (ptr, id, 6))
  118.     FatalError ("not a GIF file");
  119.  
  120.   ptr += 6;
  121.  
  122. /* Get variables from the GIF screen descriptor */
  123.  
  124.   ch = NEXTBYTE;
  125.   RWidth = ch + 0x100 * NEXTBYTE;    /* screen dimensions... not used. */
  126.   ch = NEXTBYTE;
  127.   RHeight = ch + 0x100 * NEXTBYTE;
  128.  
  129.   if (Verbose)
  130.     fprintf (stderr, "screen dims: %dx%d.\n", RWidth, RHeight);
  131.  
  132.   ch = NEXTBYTE;
  133.   HasColormap = ((ch & COLORMAPMASK) ? True : False);
  134.  
  135.   BitsPerPixel = (ch & 7) + 1;
  136.   numcols = ColorMapSize = 1 << BitsPerPixel;
  137.   BitMask = ColorMapSize - 1;
  138.  
  139.   Background = NEXTBYTE;    /* background color... not used. */
  140.  
  141.   if (NEXTBYTE)            /* supposed to be NULL */
  142.     FatalError ("corrupt GIF file (bad screen descriptor)");
  143.  
  144.  
  145. /* Read in global colormap. */
  146.  
  147.   if (HasColormap)
  148.     {
  149.       if (Verbose)
  150.     fprintf (stderr, "%s is %dx%d, %d bits per pixel, (%d colors).\n",
  151.          fname, Width, Height, BitsPerPixel, ColorMapSize);
  152.       for (i = 0; i < ColorMapSize; i++)
  153.     {
  154.       Red[i] = NEXTBYTE;
  155.       Green[i] = NEXTBYTE;
  156.       Blue[i] = NEXTBYTE;
  157.       used[i] = 0;
  158.     }
  159.       numused = 0;
  160.  
  161.     }
  162.  
  163.   else
  164.     {                /* no colormap in GIF file */
  165.       fprintf (stderr, "%s:  warning!  no colortable in this file.  Winging it.\n", cmd);
  166.       if (!numcols)
  167.     numcols = 256;
  168.       for (i = 0; i < numcols; i++)
  169.     cols[i] = (unsigned long) i;
  170.     }
  171.  
  172. /* Check for image seperator */
  173.  
  174.   if (NEXTBYTE != IMAGESEP)
  175.     FatalError ("corrupt GIF file (no image separator)");
  176.  
  177. /* Now read in values from the image descriptor */
  178.  
  179.   ch = NEXTBYTE;
  180.   LeftOfs = ch + 0x100 * NEXTBYTE;
  181.   ch = NEXTBYTE;
  182.   TopOfs = ch + 0x100 * NEXTBYTE;
  183.   ch = NEXTBYTE;
  184.   Width = ch + 0x100 * NEXTBYTE;
  185.   ch = NEXTBYTE;
  186.   Height = ch + 0x100 * NEXTBYTE;
  187.   Interlace = ((NEXTBYTE & INTERLACEMASK) ? True : False);
  188.  
  189.   if (Verbose)
  190.     fprintf (stderr, "Reading a %d by %d %sinterlaced image...",
  191.          Width, Height, (Interlace) ? "" : "non-");
  192.  
  193.   else
  194.     fprintf (stderr, "%s:  %s is %dx%d, %d colors  ",
  195.          cmd, fname, Width, Height, ColorMapSize);
  196.  
  197.  
  198. /* Note that I ignore the possible existence of a local color map.
  199.  * I'm told there aren't many files around that use them, and the spec
  200.  * says it's defined for future use.  This could lead to an error
  201.  * reading some files. 
  202.  */
  203.  
  204. /* Start reading the raster data. First we get the intial code size
  205.  * and compute decompressor constant values, based on this code size.
  206.  */
  207.  
  208.   CodeSize = NEXTBYTE;
  209.   ClearCode = (1 << CodeSize);
  210.   EOFCode = ClearCode + 1;
  211.   FreeCode = FirstFree = ClearCode + 2;
  212.  
  213. /* The GIF spec has it that the code size is the code size used to
  214.  * compute the above values is the code size given in the file, but the
  215.  * code size used in compression/decompression is the code size given in
  216.  * the file plus one. (thus the ++).
  217.  */
  218.  
  219.   CodeSize++;
  220.   InitCodeSize = CodeSize;
  221.   MaxCode = (1 << CodeSize);
  222.   ReadMask = MaxCode - 1;
  223.  
  224. /* Read the raster data.  Here we just transpose it from the GIF array
  225.  * to the Raster array, turning it from a series of blocks into one long
  226.  * data stream, which makes life much easier for ReadCode().
  227.  */
  228.  
  229.   ptr1 = Raster;
  230.   do
  231.     {
  232.       ch = ch1 = NEXTBYTE;
  233.       while (ch--)
  234.     *ptr1++ = NEXTBYTE;
  235.       if ((Raster - ptr1) > filesize)
  236.     FatalError ("corrupt GIF file (unblock)");
  237.     }
  238.   while (ch1);
  239.  
  240.   free (RawGIF);        /* We're done with the raw data now... */
  241.  
  242.   if (Verbose)
  243.     {
  244.       fprintf (stderr, "done.\n");
  245.       fprintf (stderr, "Decompressing...");
  246.     }
  247.  
  248.  
  249. /* Allocate the X Image */
  250.   Image = (byte *) malloc (Width * Height);
  251.   if (!Image)
  252.     FatalError ("not enough memory for XImage");
  253.  
  254.   theImage = XCreateImage (theDisp, theVisual, 8, ZPixmap, 0, Image,
  255.                Width, Height, 8, Width);
  256.   if (!theImage)
  257.     FatalError ("unable to create XImage");
  258.  
  259.   BytesPerScanline = Width;
  260.  
  261.  
  262. /* Decompress the file, continuing until you see the GIF EOF code.
  263.  * One obvious enhancement is to add checking for corrupt files here.
  264.  */
  265.  
  266.   Code = ReadCode ();
  267.   while (Code != EOFCode)
  268.     {
  269.  
  270. /* Clear code sets everything back to its initial value, then reads the
  271.  * immediately subsequent code as uncompressed data.
  272.  */
  273.  
  274.       if (Code == ClearCode)
  275.     {
  276.       CodeSize = InitCodeSize;
  277.       MaxCode = (1 << CodeSize);
  278.       ReadMask = MaxCode - 1;
  279.       FreeCode = FirstFree;
  280.       CurCode = OldCode = Code = ReadCode ();
  281.       FinChar = CurCode & BitMask;
  282.       AddToPixel (FinChar);
  283.     }
  284.       else
  285.     {
  286.  
  287. /* If not a clear code, then must be data: save same as CurCode and InCode */
  288.  
  289.       CurCode = InCode = Code;
  290.  
  291. /* If greater or equal to FreeCode, not in the hash table yet;
  292.  * repeat the last character decoded
  293.  */
  294.  
  295.       if (CurCode >= FreeCode)
  296.         {
  297.           CurCode = OldCode;
  298.           OutCode[OutCount++] = FinChar;
  299.         }
  300.  
  301. /* Unless this code is raw data, pursue the chain pointed to by CurCode
  302.  * through the hash table to its end; each code in the chain puts its
  303.  * associated output code on the output queue.
  304.  */
  305.  
  306.       while (CurCode > BitMask)
  307.         {
  308.           if (OutCount > 1024)
  309.         {
  310.           fprintf (stderr, "\nCorrupt GIF file (OutCount)!\n");
  311.           _exit (-1);    /* calling 'exit(-1)' dumps core, so I don't */
  312.         }
  313.           OutCode[OutCount++] = Suffix[CurCode];
  314.           CurCode = Prefix[CurCode];
  315.         }
  316.  
  317. /* The last code in the chain is treated as raw data. */
  318.  
  319.       FinChar = CurCode & BitMask;
  320.       OutCode[OutCount++] = FinChar;
  321.  
  322. /* Now we put the data out to the Output routine.
  323.  * It's been stacked LIFO, so deal with it that way...
  324.  */
  325.  
  326.       for (i = OutCount - 1; i >= 0; i--)
  327.         AddToPixel (OutCode[i]);
  328.       OutCount = 0;
  329.  
  330. /* Build the hash table on-the-fly. No table is stored in the file. */
  331.  
  332.       Prefix[FreeCode] = OldCode;
  333.       Suffix[FreeCode] = FinChar;
  334.       OldCode = InCode;
  335.  
  336. /* Point to the next slot in the table.  If we exceed the current
  337.  * MaxCode value, increment the code size unless it's already 12.  If it
  338.  * is, do nothing: the next code decompressed better be CLEAR
  339.  */
  340.  
  341.       FreeCode++;
  342.       if (FreeCode >= MaxCode)
  343.         {
  344.           if (CodeSize < 12)
  345.         {
  346.           CodeSize++;
  347.           MaxCode *= 2;
  348.           ReadMask = (1 << CodeSize) - 1;
  349.         }
  350.         }
  351.     }
  352.       Code = ReadCode ();
  353.     }
  354.  
  355.   free (Raster);
  356.  
  357.   if (Verbose)
  358.     fprintf (stderr, "done.\n");
  359.   else
  360.     fprintf (stderr, "(of which %d are used)\n", numused);
  361.  
  362.   if (fp != stdin)
  363.     fclose (fp);
  364.  
  365.   ColorDicking (fname);
  366. }
  367.  
  368.  
  369. /* Fetch the next code from the raster data stream.  The codes can be
  370.  * any length from 3 to 12 bits, packed into 8-bit bytes, so we have to
  371.  * maintain our location in the Raster array as a BIT Offset.  We compute
  372.  * the byte Offset into the raster array by dividing this by 8, pick up
  373.  * three bytes, compute the bit Offset into our 24-bit chunk, shift to
  374.  * bring the desired code to the bottom, then mask it off and return it. 
  375.  */
  376. ReadCode ()
  377. {
  378.   int RawCode, ByteOffset;
  379.  
  380.   ByteOffset = BitOffset / 8;
  381.   RawCode = Raster[ByteOffset] + (0x100 * Raster[ByteOffset + 1]);
  382.   if (CodeSize >= 8)
  383.     RawCode += (0x10000 * Raster[ByteOffset + 2]);
  384.   RawCode >>= (BitOffset % 8);
  385.   BitOffset += CodeSize;
  386.   return (RawCode & ReadMask);
  387. }
  388.  
  389.  
  390. AddToPixel (Index)
  391.      byte Index;
  392. {
  393.   if (YC < Height)
  394.     *(Image + YC * BytesPerScanline + XC) = Index;
  395.  
  396.   if (!used[Index])
  397.     {
  398.       used[Index] = 1;
  399.       numused++;
  400.     }
  401.  
  402. /* Update the X-coordinate, and if it overflows, update the Y-coordinate */
  403.  
  404.   if (++XC == Width)
  405.     {
  406.  
  407. /* If a non-interlaced picture, just increment YC to the next scan line. 
  408.  * If it's interlaced, deal with the interlace as described in the GIF
  409.  * spec.  Put the decoded scan line out to the screen if we haven't gone
  410.  * past the bottom of it
  411.  */
  412.  
  413.       XC = 0;
  414.       if (!Interlace)
  415.     YC++;
  416.       else
  417.     {
  418.       switch (Pass)
  419.         {
  420.         case 0:
  421.           YC += 8;
  422.           if (YC >= Height)
  423.         {
  424.           Pass++;
  425.           YC = 4;
  426.         }
  427.           break;
  428.         case 1:
  429.           YC += 8;
  430.           if (YC >= Height)
  431.         {
  432.           Pass++;
  433.           YC = 2;
  434.         }
  435.           break;
  436.         case 2:
  437.           YC += 4;
  438.           if (YC >= Height)
  439.         {
  440.           Pass++;
  441.           YC = 1;
  442.         }
  443.           break;
  444.         case 3:
  445.           YC += 2;
  446.           break;
  447.         default:
  448.           break;
  449.         }
  450.     }
  451.     }
  452. }
  453.  
  454.  
  455. /*************************/
  456. ColorDicking (fname)
  457.      char *fname;
  458. {
  459.   /* we've got the picture loaded, we know what colors are needed. get 'em */
  460.  
  461.   register int i, j;
  462.   static byte lmasks[8] =
  463.   {0xff, 0xfe, 0xfc, 0xf8, 0xf0, 0xe0, 0xc0, 0x80};
  464.   byte lmask, *ptr;
  465.  
  466.  
  467.   if (!HasColormap)
  468.     return;
  469.   /* no need to allocate any colors if no colormap in GIF file */
  470.  
  471.   /* Allocate the X colors for this picture */
  472.  
  473.   if (nostrip)
  474.     {                /* nostrip was set.  try REAL hard to do it */
  475.       for (i = j = 0; i < numcols; i++)
  476.     {
  477.       if (used[i])
  478.         {
  479.           defs[i].red = Red[i] << 8;
  480.           defs[i].green = Green[i] << 8;
  481.           defs[i].blue = Blue[i] << 8;
  482.           defs[i].flags = DoRed | DoGreen | DoBlue;
  483.           if (!XAllocColor (theDisp, theCmap, &defs[i]))
  484.         {
  485.           j++;
  486.           defs[i].pixel = 0xffff;
  487.         }
  488.           cols[i] = defs[i].pixel;
  489.         }
  490.     }
  491.  
  492.       if (j)
  493.     {            /* failed to pull it off */
  494.       XColor ctab[256];
  495.       int dc;
  496.  
  497.       dc = (dispcells < 256) ? dispcells : 256;
  498.  
  499.       fprintf (stderr, "failed to allocate %d out of %d colors.  Trying extra hard.\n", j, numused);
  500.  
  501.       /* read in the color table */
  502.       for (i = 0; i < dc; i++)
  503.         ctab[i].pixel = i;
  504.       XQueryColors (theDisp, theCmap, ctab, dc);
  505.  
  506.       /* run through the used colors.  any used color that has a pixel
  507.          value of 0xffff wasn't allocated.  for such colors, run through
  508.          the entire X colormap and pick the closest color */
  509.  
  510.       for (i = 0; i < numcols; i++)
  511.         if (used[i] && cols[i] == 0xffff)
  512.           {            /* an unallocated pixel */
  513.         int d, mdist, close;
  514.         unsigned long r, g, b;
  515.  
  516.         mdist = 100000;
  517.         close = -1;
  518.         r = Red[i];
  519.         g = Green[i];
  520.         b = Blue[i];
  521.         for (j = 0; j < dc; j++)
  522.           {
  523.             d = abs (r - (ctab[j].red >> 8)) +
  524.               abs (g - (ctab[j].green >> 8)) +
  525.               abs (b - (ctab[j].blue >> 8));
  526.             if (d < mdist)
  527.               {
  528.             mdist = d;
  529.             close = j;
  530.               }
  531.           }
  532.         if (close < 0)
  533.           FatalError ("simply can't do it.  Sorry.");
  534.         bcopy (&defs[close], &defs[i], sizeof (XColor));
  535.         /*if (!XAllocColor(theDisp,theCmap,&defs[close])) { 
  536.            printf("Big Problem\n");} */
  537.         used[i] = 6;
  538.         cols[i] = ctab[close].pixel;
  539.           }
  540.     }            /* end 'failed to pull it off' */
  541.     }
  542.  
  543.   else
  544.     {                /* strip wasn't set, do the best auto-strip */
  545.       j = 0;
  546.       while (strip < 8)
  547.     {
  548.       lmask = lmasks[strip];
  549.       for (i = 0; i < numcols; i++)
  550.         if (used[i])
  551.           {
  552.         defs[i].red = (Red[i] & lmask) << 8;
  553.         defs[i].green = (Green[i] & lmask) << 8;
  554.         defs[i].blue = (Blue[i] & lmask) << 8;
  555.         defs[i].flags = DoRed | DoGreen | DoBlue;
  556.         if (!XAllocColor (theDisp, theCmap, &defs[i]))
  557.           break;
  558.         cols[i] = defs[i].pixel;
  559.           }
  560.  
  561.       if (i < numcols)
  562.         {            /* failed */
  563.           strip++;
  564.           j++;
  565.           for (i--; i >= 0; i--)
  566.         if (used[i])
  567.           XFreeColors (theDisp, theCmap, cols + i, 1, 0L);
  568.         }
  569.       else
  570.         break;
  571.     }
  572.  
  573.       if (j && strip < 8)
  574.     fprintf (stderr, "%s:  %s stripped %d bits\n", cmd, fname, strip);
  575.  
  576.       if (strip == 8)
  577.     {
  578.       fprintf (stderr, "UTTERLY failed to allocate the desired colors.\n");
  579.       for (i = 0; i < numcols; i++)
  580.         cols[i] = i;
  581.     }
  582.     }
  583.  
  584.   ptr = Image;
  585.   for (i = 0; i < Height; i++)
  586.     for (j = 0; j < Width; j++, ptr++)
  587.       *ptr = (byte) cols[*ptr];
  588. }
  589.